/**
 * 使用原生 canvas 2d 制作的背景图层
 */

import { BaseComp } from '../../../common/component/comp';

const lineStyles = [
	// { size: 1.25, style: "pattern", color: { h: 210, s: 100, l: 70, a: 0.5 } },
	// { size: 2.5, style: "pattern", color: { h: 190, s: 90, l: 50, a: 0.3 } },
	{ size: 5, style: "pattern", color: { h: 210, s: 70, l: 60, a: 0.2 } },
	{ size: 10, style: "pattern", color: { h: 310, s: 80, l: 55, a: 0.15 } },
	{ size: 20, style: "pattern", color: { h: 200, s: 25, l: 35, a: 0.12 } },
	{ size: 20, style: "pattern", color: { h: 210, s: 20, l: 40, a: 0.12 } },
	{ size: 40, style: "pattern", color: { h: 190, s: 40, l: 50, a: 0.12 } },
	{ size: 80, style: "pattern", color: { h: 220, s: 50, l: 60, a: 0.12 } },
	{ size: 40, style: "glitches", color: { h: 300, s: 100, l: 50, a: 0.3 } },
	{ size: 20, style: "glitches", color: { h: 210, s: 100, l: 50, a: 0.3 } },
	{ size: 60, style: "glitches", color: { h: 30, s: 100, l: 50, a: 0.3 } }
];

class CoreBg extends BaseComp {
	tickCount = 0;
	/** @type {CanvasRenderingContext2D} */
	ctx = null;

	/** @type {Line[]} */
	lines = [];

	constructor(args) {
		super(args.parent);
		this.left = args.x;
		this.top = args.y;
		this.width = args.width;
		this.height = args.height;
		this.centerX = args.centerX;
		this.centerY = args.centerY;
		this.zlevel = args.zlevel;
		this.canvas = this.initDom();

		this.ctx = this.canvas.getContext("2d");
		this.lines = this.generateLines(args.amount || 40);
	}

	initDom() {
		const {left, top, width, height, zlevel} = this;

		const main = document.getElementById('main');
		main.style.width = width + 'px';
		main.style.height = height + 'px';

		let content = document.createElement('canvas');
		content.id = 'coreBg';
		content.width = width;
		content.height = height;
		content.style.position = 'absolute';
		content.style.overflow = 'hidden';
		content.style.width = width + 'px';
		content.style.height = height + 'px';
		content.style.left = left + 'px';
		content.style.top = top + 'px';
		content.style.zIndex = zlevel + '';
		content.style.mixBlendMode = 'lighten';
		main.appendChild(content);
		return content;
	}

	tick() {
		const {ctx, lines, width, height} = this;
		let id = this.tickCount ++;

		if (!(id % 3)) {
			// clear
			ctx.fillStyle = '#0002';
			ctx.fillRect(0, 0, width, height);

			// lines
			lines.forEach(line => {
				line.draw(ctx);
				if (!(id % 5) && Math.random() > 0.95) {
					line.mutatePath();
				}
			});
		}
	}

	generateLines(amount) {
		const { centerX, centerY } = this;
		let lines = [];

		for (let i = 0; i < amount; i += 1) {
			let style = lineStyles[(Math.random() ** 1.5 * lineStyles.length) | 0];
			lines.push(
				new Line(
					centerX,
					centerY,
					style.size,
					500 + Math.random() * 1000,
					style.color,
					style.style
				)
			);
		}
		return lines;
	}
}

/**
 * 随机生长方向
 * @param {number} size 线段长度
 */
function randomLineGenerators(size) {
	let direction = (Math.random() * 8) | 0;
	switch (direction) {
	case 7:
		return {
			line: `l-${size}-${size}`,
			mag: Math.hypot(size, size)
		};
	case 6:
		return {
			line: `l-${size},${size}`,
			mag: Math.hypot(size, size)
		};
	case 5:
		return {
			line: `l${size},${size}`,
			mag: Math.hypot(size, size)
		};
	case 4:
		return {
			line: `l${size}-${size}`,
			mag: Math.hypot(size, size)
		};
	case 3:
		return {
			line: `v-${size}`,
			mag: size
		};
	case 2:
		return {
			line: `v${size}`,
			mag: size
		};
	case 1:
		return {
			line: `h-${size}`,
			mag: size
		};
	default:
		return {
			line: `h${size}`,
			mag: size
		}
	}
}

class Line {

	/** @type {Path2D} */
	path = null;
	finished = true;
	offSet = 0;
	/** @type {{path: string; mag: number;}} */
	line = {
		path : null,
		mag : 0
	};

	constructor(x, y, size, length, color, style = "pattern") {
		this.size = size;
		this.length = length;
		this.color = color;
		this.style = style;
		this.origin = `M${x},${y}`;
		this.offSetSpeed = length / size;
	}
	generate() {
		let mag = 0;
		let paths = [];
		for (let i = 0; i < this.length; i += 1) {
			let fragment = randomLineGenerators(this.size);
			paths.push(fragment.line);
			mag += fragment.mag;
		}
		this.line.path = this.origin + paths.join('');
		this.line.mag = mag;
		this.path = new Path2D(this.line.path);
		this.finished = false;
		this.offSet = 0;
		return this;
	}
	renderStyle(style, ctx) {
		if (style === "glitches") {
			ctx.lineDashOffset = this.line.mag + this.offSet;
			ctx.setLineDash([
				this.size ** 1.5,
				(this.line.mag / this.length) * this.size ** 2
			]);
			this.offSet += 20;
			ctx.lineWidth = 2;
			return this;
		} else if (style === "pattern") {
			const {mag} = this.line;
			ctx.lineDashOffset = mag - this.offSet;
			ctx.setLineDash([mag, mag]);
			ctx.lineWidth = 0.2;

			this.offSet += 10;
			if (this.offSet > 2 * mag) {
				this.offSet = 2 * mag;
				this.finished = true;
			}
		}
	}
	mutatePath() {
		let lineFragment = this.line.path.split(" ").slice(1);
		lineFragment[(Math.random() * lineFragment.length) | 0] = randomLineGenerators(this.size).line;
		this.line.path = `${this.line.path.split(" ")[0]} ${lineFragment.join(" ")}`;
		this.path = new Path2D(this.line.path);
	}
	draw(ctx) {
		if (this.finished) {
			this.generate();
		}

		ctx.strokeStyle = `hsla(${this.color.h}deg,${this.color.s}%,${this.color.l}%,${this.color.a})`;
		this.renderStyle(this.style, ctx);
		ctx.lineCap = "round";
		ctx.lineJoin = "round";
		ctx.stroke(this.path);

		return this;
	}
}

export {
	CoreBg
};
